/*
本源码用于实现一个时钟

*/

#include <8052.h>
#include "misc.h"

#define FOSC 11059200L //晶振时钟

void timer_show();
void clearDshow();

//时间结构体
struct TIME
{
    char Hour;
    char Minute;
    char Second;
} timer = {0, 0, 0};

//定时器低位与高位
char TIME_TL_DATA, TIME_TH_DATA;
//定时器中断次数
char TIME_COUNT = 0;

//入口方法
void timer_go(void)
{
    //给TL&TH赋值，除以20是50ms，以最小的中断次数减少中断代码带来的误差（不能再小于20了，因为8位最多65536）
    unsigned int t1ms = (65536 - (FOSC / 12 / 20)); //=65536-46080
    TIME_TL_DATA = (unsigned char)t1ms;
    t1ms = t1ms >> 8;
    TIME_TH_DATA = (unsigned char)t1ms;

    //开中断
    TMOD = 0x01;        //开启一个定时器
    TL0 = TIME_TL_DATA; //reload timer0 low byte
    TH0 = TIME_TH_DATA; //reload timer0 high byte
    TR0 = 1;            //timer0 start running
    ET0 = 1;            //enable timer0 interrupt
    EA = 1;             //open global interrupt switch
    while (1)
    {
        timer_show();
    }
}

//定时器0 //用于显示数码管
void timer_interrupt1(void) __interrupt 1
{
    //重新赋值再来
    TL0 = TIME_TL_DATA;
    TH0 = TIME_TH_DATA;
    TIME_COUNT++;
    if (TIME_COUNT == 20)
    { //跑完1000ms  10ms X 100 = 1000ms = 1s
        TIME_COUNT = 0;
        timer.Second++;
        if (timer.Second >= 60)
        {
            timer.Second = 0;
            timer.Minute++;
        }
        if (timer.Minute >= 60)
        {
            timer.Minute = 0;
            timer.Hour++;
        }
        if (timer.Hour >= 24)
        {
            timer.Hour = 0;
        }
    }
}

//显示数码管数据
void timer_show()
{
    char idx = 0;
    //偶数秒显示点
    char isShowDot = timer.Second % 2 == 0;

    //小时十位
    P0 = 0b111110;
    P2_7 = 1; //开启位选 //低电位显示，数码管位置与二进制是反的
    P2_7 = 0; //关闭位选
    idx = timer.Hour / 10;
    P0 = TBL_DIGITAL_DISPALY[idx];
    P2_6 = 1; //开启段选
    P2_6 = 0; //关闭段选
    delay(1);
    clearDshow();
    //小时个位
    P0 = 0b111101;
    P2_7 = 1; //开启位选 //低电位显示，数码管位置与二进制是反的
    P2_7 = 0; //关闭位选
    idx = timer.Hour % 10;
    P0 = isShowDot ? TBL_DIGITAL_DISPALY[idx] | 0b10000000 : TBL_DIGITAL_DISPALY[idx];
    P2_6 = 1; //开启段选
    P2_6 = 0; //关闭段选
    delay(1);
    clearDshow();

    //分钟十位
    P0 = 0b111011;
    P2_7 = 1; //开启位选 //低电位显示，数码管位置与二进制是反的
    P2_7 = 0; //关闭位选
    idx = timer.Minute / 10;
    P0 = TBL_DIGITAL_DISPALY[idx];
    P2_6 = 1; //开启段选
    P2_6 = 0; //关闭段选
    delay(1);
    clearDshow();
    //分钟个位
    P0 = 0b110111;
    P2_7 = 1; //开启位选 //低电位显示，数码管位置与二进制是反的
    P2_7 = 0; //关闭位选
    idx = timer.Minute % 10;
    P0 = isShowDot ? TBL_DIGITAL_DISPALY[idx] | 0b10000000 : TBL_DIGITAL_DISPALY[idx];
    P2_6 = 1; //开启段选
    P2_6 = 0; //关闭段选
    delay(1);
    clearDshow();

    //秒钟十位
    P0 = 0b101111;
    P2_7 = 1; //开启位选 //低电位显示，数码管位置与二进制是反的
    P2_7 = 0; //关闭位选
    idx = timer.Second / 10;
    P0 = TBL_DIGITAL_DISPALY[idx];
    P2_6 = 1; //开启段选
    P2_6 = 0; //关闭段选
    delay(1);
    clearDshow();
    //秒钟个位
    P0 = 0b011111;
    P2_7 = 1; //开启位选 //低电位显示，数码管位置与二进制是反的
    P2_7 = 0; //关闭位选
    idx = timer.Second % 10;
    P0 = TBL_DIGITAL_DISPALY[idx];
    P2_6 = 1; //开启段选
    P2_6 = 0; //关闭段选
    delay(1);
    clearDshow();
}

//清除段选，因为数据锁在段选里
//在第二次开启的时候会影响显示
void clearDshow()
{
    P0 = 0;
    P2_6 = 1; //开启段选
    P2_6 = 0; //关闭段选
}